<?php

namespace App\HttpController\Api;

use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\HttpAnnotation\AnnotationController;

use EasySwoole\EasySwoole\Core;
use EasySwoole\EasySwoole\Trigger;
use EasySwoole\Http\Message\Status;
use EasySwoole\HttpAnnotation\Exception\Annotation\ParamValidateError;

use App\Think\Org\Auth;

class ApiBase extends AnnotationController
{

    protected $auth = null;
    protected $noNeedLogin = [];

    function index()
    {
        $this->actionNotFound('index');
    }

    function onRequest(?string $action): ?bool
    {
        // 解决跨域
        $this->response()->withHeader('Access-Control-Allow-Origin', '*');
        $this->response()->withHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
        $this->response()->withHeader('Access-Control-Allow-Credentials', 'true');
        $this->response()->withHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
        if (!parent::onRequest($action) || $this->request()->getMethod() === 'OPTIONS') return false;

        //初始化用户授权
        // $this->auth = Auth::instance(['client_ip'=>$this->clientRealIP()]);
        // if(!self::checkAuth($action, $this->noNeedLogin)) {
        //     $this->error('请先登录');
        //     return false;
        // }

        //根据请求头Token，获取用户登录信息
        // $token = $this->request()->getHeader('token');
        $token = $this->request()->getRequestParam('token');
        // $this->auth = Auth::instance(['client_ip'=>$this->clientRealIP()]);
        $this->auth = new Auth(['client_ip'=>$this->clientRealIP()]);
        $hasLogin = $this->auth->init($token);
        //白名单判断
        if(in_array($action, $this->noNeedLogin) || $this->noNeedLogin == ['*']) return true;
        if(!$hasLogin){
            $this->error('请先登录');
            return false;
        } 
        return true;
    }

    //返回成功json
    protected function success($msg, $data=[], $code=1){
        $this->writeJson($code, $data, $msg);
    }
    //返回错误json
    protected function error($msg, $code=0, $data=[]){
        $this->writeJson($code, $data, $msg);
    }
    //重写默认的json方法
    protected function writeJson($code = 0, $result = null, $msg = null)
    {
        if (!$this->response()->isEndResponse()) {
            $data = Array(
                "code" => $code,
                "msg"  => $msg,
                "data" => $result,
                "time" => time()
            );
            $this->response()->write(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
            $this->response()->withHeader('Content-type', 'application/json;charset=utf-8');
            $statusCode = Status::CODE_BAD_REQUEST;
            if($code>0) $statusCode = Status::CODE_OK;
            if($code == -500) $statusCode = Status::CODE_OK;
            $this->response()->withStatus($statusCode);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 限制请求次数
     * @param  string $cacheKey   缓存Key
     * @param  int    $limitCount 限制次数
     * @param  int    $cacheTime  缓存过期时间
     * @param  string $msg        提示信息
     */
    protected function requestLimit($cacheKey, $limitCount, $cacheTime, $msg): ?bool
    {
        $optTime = cache($cacheKey);
        if($optTime>$limitCount){
            $this->error(__($msg));
            return false;
        } 
        cache($cacheKey,$optTime+1, $cacheTime);
        return true;
    }

    /**
     * 操作权限&&登录判断
     * @param  string $action      操作方法
     * @param  array  $noNeedLogin 白名单方法
     * @return bool
     */
    protected function checkAuth($action, $noNeedLogin){
        //获取登入信息
        // $token = $this->request()->getHeader('token');
        $token = $this->request()->getRequestParam('token');
        $hasLogin = $this->auth->init($token);
        //白名单判断
        if(in_array($action, $noNeedLogin) || $noNeedLogin == ['*']) return true;
        if(!$hasLogin) return false;
        return true;
    }

    /**
     * 404错误提示
     * @param  string $action 方法名
     * @return json
     */
    protected function actionNotFound(?string $action): void
    {
        $this->error('找不到控制器或方法');
    }

    /**
     * 获取用户的真实IP
     * @param string $headerName 代理服务器传递的标头名称
     * @return string
     */
    protected function clientRealIP($headerName = 'x-real-ip')
    {
        $server = ServerManager::getInstance()->getSwooleServer();
        $client = $server->getClientInfo($this->request()->getSwooleRequest()->fd);
        $clientAddress = $client['remote_ip'];
        $xri = $this->request()->getHeader($headerName);
        $xff = $this->request()->getHeader('x-forwarded-for');
        if ($clientAddress === '127.0.0.1') {
            if (!empty($xri)) {  // 如果有xri 则判定为前端有NGINX等代理
                $clientAddress = $xri[0];
            } elseif (!empty($xff)) {  // 如果不存在xri 则继续判断xff
                $list = explode(',', $xff[0]);
                if (isset($list[0])) $clientAddress = $list[0];
            }
        }
        return $clientAddress;
    }

    /**
     * 获取输入值
     * @param  string $name    参数名
     * @param  string $default 默认值
     * @return string
     */
    protected function input($name, $default = null) {
        $value = $this->request()->getRequestParam($name);
        return $value ?? $default;
    }

    /**
     * 异常处理
     * @param  \Throwable $throwable 异常对象
     * @return json
     */
    protected function onException(\Throwable $throwable): void
    {
        if ($throwable instanceof ParamValidateError) {
            $msg = $throwable->getValidate()->getError()->getErrorRuleMsg();
            // $this->writeJson(400, null, "{$msg}");
            $this->error("{$msg}", -400);
        } else {
            if (Core::getInstance()->isDev()) {
                // $this->writeJson(500, null, $throwable->getMessage());
                $this->error($throwable->getMessage(), -500);
            } else {
                Trigger::getInstance()->throwable($throwable);
                // $this->writeJson(500, null, '系统内部错误，请稍后重试');
                $this->error('系统内部错误，请稍后重试', -500);
            }
        }
    }

}
